#!/usr/bin/perl -w

BEGIN {
        push @INC,$ENV{CODEMGR_LIBS} if exists($ENV{CODEMGR_LIBS});
	if(!exists($ENV{PROJECTS_ROOT})) {
		print STDERR "Error: Required environment variable 'PROJECTS_ROOT' is not configured.\n";
		exit 1;
	}
	my %grnam=();
	open(F,"/etc/group");
	while(<F>) {
		my @F=split(/:/,$_);
		$grnam{$F[0]}=$F[2];
	}
	close(F);

	sub getgrnam2($) {
		if(exists($grnam{$_[0]})) {
			return $grnam{$_[0]};
		}
		return undef;
	}
}

END {
	print "$_\n" foreach(@E);

}

use Cwd;
use codemgr2 qw(parse_rlog load_config get_project get_email_addr);
use pv;
use File::Basename;
use Data::Dumper;
use Fcntl ":flock";

#########################################################################
# If any directories are missing we create them now...			#
#########################################################################

sub mk_missing_dirs($) {
my $full=$_[0];

	$full =~ s/\/{2,}//g; # remove multiple duplicates
	my $path="";
	my @bits=split(/\//,$full);
	for my $cbit (@bits) {
		next if !defined($cbit);
		next if !length($cbit);
		$path.="/$cbit";
		if(! -d $path) {
			mkdir($path,0755);
		}
	}
}

@L=();
@E=();

sub errormsg {
	push @E,$_[0];
	exit($_[1]) if defined($_[1]);
}

$_PRG=basename($0);
$project=$ARGV[0];
if(!defined($project)) {
	print STDERR "Usage: $_PRG project\n";
	exit 1;
}

$PROJECTS_ROOT=$ENV{PROJECTS_ROOT};
$PROJECT_SOURCE="$PROJECTS_ROOT/$project";
$PROJECT_META="$PROJECT_SOURCE/.meta";
$ARG_verbose=0;
$cfg=load_config($PROJECT_META);
errormsg("Errors whilst loading source configuration - aborting.",3) if !defined($cfg);

#########################################################################
# Check to see if a PROXY_PROMOTE_FILE config item exists, and that	#
# the file in question actually exists.					#
#########################################################################

if(!exists($cfg->{PROXY_PROMOTE_FILE})) {
	errormsg("No 'PROXY_PROMOTE_FILE' setting for project!",1);
}

$queue=$cfg->{PROXY_PROMOTE_FILE}->[0];
if(! -f $queue) {
	print "No queue file \"$queue\"\n";
	exit(0);
}

#########################################################################
# File exists - so continue for the moment.				#
#########################################################################

chdir($cfg->{SOURCE_ROOT}->[0]) or 
	errormsg("Unable to change directory to '" . $cfg->{SOURCE_ROOT}->[0] . "' - aborting.",1);

#########################################################################
# Check current directory is part of a development instance		#
#########################################################################

@r=get_project($cfg->{SOURCE_ROOT}->[0],undef);

if(defined($r[0])) {
        $project=$r[0];
        $sdir=$r[1];
} else {
        if($r[1]==1) {
                errormsg("No project owning this directory has been found!",1);
        }
        if($r[1]==2) {
                errormsg("Multiple projects owning this directory have been found!",1);
        }
        errormsg($r[2],2);
        exit 1;
}

#########################################################################
# If get here the current directory is valid - so get lock on the queue	#
# file before promoting the files contained in it.			#
#########################################################################

open(FD,"$queue") or errormsg("Unable to open \"$queue\" for reading:\n$!",1);
flock(FD,LOCK_EX);
@F=<FD>;

#########################################################################
# Read all records - but do not unlock as yet.				#
#########################################################################

if(exists($cfg->{PROXY_PROMOTE_PERMS})) {
	my @F=split(/,/,$cfg->{PROXY_PROMOTE_PERMS}->[0]);
	if($F[0] !~ /^\d+$/) {
		$promote_user=getpwnam($F[0]);
	} else {
		$promote_user=$F[0];
		$promote_user=-1 if !defined($promote_user);
	}
	if($F[1] !~ /^\d+$/) {
		$promote_group=getgrnam2($F[1]);
		$promote_group=-1 if !defined($promote_group);
	} else {
		$promote_group=$F[1];
		$promote_group=-1 if !defined($promote_group);
	}
	if(defined($F[2])) {
		$promote_perms=oct($F[2]);
	} else {
		$promote_perms=0555;
	}
}

%usermap=();
for $cfile (@F) {
	chomp($cfile);
	($user,$ver,$fn)=split(/\|/,$cfile);
	next if !defined($user);
	$usermap{$user}=[] if !exists($usermap{$user});
	#########################################################
	# Check to see if the RCS versino file exists, and	#
	# add to error list if not.				#
	#########################################################
	if(! -e "$sdir/$fn,v" && ! -e "$sdir/$fn,pv") {
		errormsg("File \"fn\" does not exist code control - ignoring.");
		push @{$usermap{$user}},"File \"fn\" does not exist under code control - ignoring.";
		next;
	}
	if(-e "$sdir/$fn,v") {
		$rloginfo=parse_rlog("$sdir/$fn,v",1);
	} else {
		$rloginfo=parse_rlog("$sdir/$fn,pv",2);
	}
	if(!defined($rloginfo)) {
		errormsg("Error parsing code control information for \"$fn\".");
		push @{$usermap{$user}},"Error parsing code control information for \"$fn\".";
		next;
	}
	#########################################################
	# Ensure specified release exists, and abort if not.	#
	#########################################################

	if(!scalar(grep {/^$ver$/} @{$rloginfo->{revlist}})) {
		errormsg("File \"$fn\" does not have version '$ver' - ignoring.");
		push @{$usermap{$user}},"File \"$fn\" does not have version '$ver' - ignoring.";
		next;
	}
	if(! exists($cfg->{REPOS_TYPE}) || ($cfg->{REPOS_TYPE}->[0] eq "1")) {
		if(!open($fd2,"co -p$ver $sdir/$fn,v 2>/dev/null|")) {
			errormsg("RCS error when print version '$ver' of '$fn' - ignoring.");
		}
	} else {
		pv::get(FILE=>"/tmp/promote_$$.txt", PVFILE=>"$sdir/$fn,pv",CHECKOUT=>0,LOCK=>0,VERSION=>$ver);
		if(! -f "/tmp/promote_$$.txt") {
			errormsg("PV error when getting version '$ver' of '$fn' - ignoring.");
			unlink("/tmp/promote_$$.txt");
		}
		open($fd2,"/tmp/promote_$$.txt");
		unlink("/tmp/promote_$$.txt");
	}

	$_cdir=$cfg->{SOURCE_ROOT}->[0] . "/" . dirname($fn);
	$_cdir =~ s!/dev/!/test/!;
	if(! -d $_cdir) {
		mk_missing_dirs($_cdir);
	}
	$fname="$_cdir/" . basename($fn) . ".tmp";
	$fname2="$_cdir/" . basename($fn);
	if(!open($fd3,">$fname")) {
		errormsg("Unable to write to '$fname' - ignoring.");
		push @{$usermap{$user}},"Unable to write to '$fname' - ignoring.";
		next;
	}
	$ok=1;
	while(<$fd2>) {
		if(! print $fd3 $_) {
			errormsg("Failed writing to '$fname' - ignoring.");
			push @{$usermap{$user}},"Failed writing to '$fname' - ignoring.";
			unlink($fname);
			$ok=0;
			next;
		}
	}
	close($fd2); close($fd3);
	if($ok) {
		unlink($fname2);
		rename($fname,$fname2);
		chmod 0555,$fname2;
		if(defined($promote_user)) {
			chown $promote_user,$promote_group,$fname2;
			chmod $promote_perms,$fname2;
		}
	}
	push @L,"File '$fname2' version '$ver' installed for '$user'.";
	push @{$usermap{$user}},"File '$fname2' version '$ver' successfully promoted.";
	print "File '$fname2' version '$ver' installed for '$user'.\n";
}
open(FD,">$queue");
chmod 0664,$queue;
flock(FD,LOCK_UN);
close(FD);

if(scalar(@E)==0 && scalar(@L)==0) {
	exit 0;
}
if(exists($cfg->{GET_EMAIL_ADDR})) {
	for $user (keys(%usermap)) {
		my $email=get_email_addr($cfg,$user);
		next if !defined($email);
		open($fd,"|mailx -s \"Code Promoter Notification\" -r do_not_reply\@stbe905a $email");
		if(defined($fd)) {
			print $fd "$_\n" for (@{$usermap{$user}});
			close($fd);
		}
	}
}

if(exists($cfg->{PROXY_PROMOTE_NOTIFY})) {
	@A=split(/,/,$cfg->{PROXY_PROMOTE_NOTIFY}->[0]);
	if(@A) {
		$ofile="/tmp/outfile.$$";

		if(@L) {
			open(FD,">>$ofile");
			print FD "Log  : $_\n" foreach(@L);
			print FD "\n";
			close(FD);
		}

		if(@E) {
			open(FD,">>$ofile");
			print FD "Error: $_\n" foreach(@E);
			print FD "\n";
			close(FD);
		}
		
		$cmd="cat $ofile | " . 'mailx -s "Code Promoter Notification" -r do_not_reply@stbe905a ';
		$cmd.=join(" ",@A);
		system($cmd);
		unlink $ofile;
	}
}
exit(0);
 
